package nirvana.core.generateCode;

import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.Column;
import nirvana.core.domains.ann.AccEntity;
import nirvana.core.domains.enums.EntityType;
import nirvana.core.utils.ClassUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * 【描 述】：
 * 【环 境】：J2SE 17
 * 【详 细】：
 *
 * @author 李松林
 * @version v1.0 2023-05-22 新建
 * @since 2023-05-22
 */
@Service
public class GenerateCodeFile {

    private final GenerateFile generateFile;

    public GenerateCodeFile(GenerateFile generateFile) {
        this.generateFile = generateFile;
    }


    /**
     * 构建代码
     */
    public void generateCode(CodeGenerateParam generateParam) {

        String pojoPackage = generateParam.getPojoPackage();

        /*
        1.获取entity包下的全部实体类
        2.轮询，并判断实体的类型
        3.
         */
        String entityPackage = pojoPackage + ".entity";

        //获取到pojo包下的全部Entity类
        List<Class> list = ClassUtil.getAllClasses(entityPackage);

        for (Class<?> aClass : list) {
            String className = aClass.getSimpleName();
            AccEntity entityAn = aClass.getAnnotation(AccEntity.class);



            if (entityAn==null){
                continue;
            }
            //构建代码的参数
            GenerateFileParam param = new GenerateFileParam();
            param.setClassName(className);
            if (entityAn != null) {
                param.setEntityName(entityAn.value());
                EntityType type = entityAn.type();

                param.setEntityType(entityAn.type());
                //判断是否未业务实体
                if (type.equals(EntityType.SERVICE_ENTITY)) {
                    param.setIsServerEntity(Boolean.TRUE);
                }
            }

            //根据类名称转出表名称
            String tableName = getTableName(aClass);
            param.setTableName(tableName);


            //获取类中的全部字段
            Field[] fields = aClass.getDeclaredFields();
            List<CodeGenerateFieldParam> fieldParamList = new ArrayList<>();
            for (Field field : fields) {
                CodeGenerateFieldParam fieldParam = new CodeGenerateFieldParam();

                String fieldName = field.getName();

                Class<?> fieldType = field.getType();
                String fieldTypeSimpleName = fieldType.getSimpleName();


                fieldParam.setFieldName(fieldName);
                fieldParam.setClassName(fieldTypeSimpleName);

                Column column = field.getAnnotation(Column.class);
                if (column != null) {

                    boolean notNull = !column.isNull();
                    String defaultValue = column.defaultValue();


                    //必须是不能为空，且没有默认值的参数，才再参数校验
                    fieldParam.setNotNull(notNull && "DEFAULT".equals(defaultValue));

                    //备注
                    String comment = column.comment();
                    fieldParam.setComment(comment);

                    int length = column.length();
                    fieldParam.setLength(length);

                }

                fieldParamList.add(fieldParam);
            }
            param.setFieldList(fieldParamList);


            BeanUtils.copyProperties(generateParam,param);
            generateFile.generateGroupFile(param);
        }
    }

    /**
     * 获取表名称。首先尝试从 @TableName 注解获取，如果未使用注解，则根据类名转换规则获取。
     *
     * @param clazz 实体类的 Class 对象
     * @return 表名称
     */
    public static String getTableName(Class<?> clazz) {
        // 尝试从 @TableName 注解获取表名
        if (clazz.isAnnotationPresent(TableName.class)) {
            TableName tableName = clazz.getAnnotation(TableName.class);
            return tableName.value();
        }
        // 注解未指定时，根据类名转换规则获取表名
        return camelCaseToUnderscore(clazz.getSimpleName());
    }

    /**
     * 将驼峰命名转换为下划线命名。
     *
     * @param input 输入的字符串
     * @return 转换后的字符串
     */
    private static String camelCaseToUnderscore(String input) {
        // 除首个字母外，前面有大写字母的地方，前面加下划线，然后全部转为小写
        String underscore = input.replaceAll("([A-Z])", "_$1").toLowerCase();
        // 如果结果字符串以下划线开头，去除下划线
        return underscore.startsWith("_") ? underscore.substring(1) : underscore;
    }



}
